﻿using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine.UIElements;

namespace winS.UnityEditor.UIElement
{
    /// <summary>
    /// 泛型枚举字段
    /// </summary>
    public class EnumField<T> : EditorField<T> where T : Enum
    {
        private bool hasAliasMap => aliasMap != null && aliasMap.Count != 0;
        private bool hasHideFlag => hideFlags != null && hideFlags.Count != 0;

        private IList<T> hideFlags;
        private IDictionary<T, string> aliasMap;
        private readonly FieldInfo[] fieldInfos;
        private readonly DropdownField dropdownField;
        private readonly List<string> visibleNameList;
        private readonly List<T> visibleFieldInfoList;
        private readonly Dictionary<string, string> aliasDictionary = new Dictionary<string, string>();

        internal EnumField(ElementFactory elementFactory) : base(elementFactory)
        {
            fieldInfos = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static);
            visibleFieldInfoList = new List<T>(fieldInfos.Length);
            visibleNameList = new List<string>(fieldInfos.Length);
            foreach (var fieldInfo in fieldInfos)
            {
                visibleNameList.Add(fieldInfo.Name);
                visibleFieldInfoList.Add((T)fieldInfo.GetValue(null));
            }

            Add(dropdownField = EditorElementUtility.elementFactory.CreateDropdownField(visibleNameList, OnNameChangeCallback));
            EditorElementUtility.ApplySubFieldStyle(dropdownField);

            RegisterCallback<ClickEvent>(ClickCallback);
        }

        public void SetHideFlag(IList<T> hideFlags)
        {
            this.hideFlags = hideFlags;
            Update();
        }
        public void SetAliasMap(IDictionary<T, string> aliasMap)
        {
            this.aliasMap = aliasMap;
            Update();
        }

        public override void SetValueWithoutNotify(T value)
        {
            base.SetValueWithoutNotify(value);
            UpdateDisplayValue(value);
        }

        protected override void SetValue(T value)
        {
            base.SetValue(value);
            UpdateDisplayValue(value);
        }

        private void Update()
        {
            visibleNameList.Clear();
            aliasDictionary.Clear();

            if (!hasHideFlag)//没有要隐藏的枚举
            {
                if (hasAliasMap)//有别名
                {
                    for (int i = 0; i < fieldInfos.Length; i++)
                    {
                        FieldInfo fieldInfo = fieldInfos[i];
                        if (aliasMap.TryGetValue((T)fieldInfo.GetValue(null), out string alias))
                        {
                            visibleNameList.Add(alias);
                            aliasDictionary.Add(fieldInfo.Name, alias);
                            continue;
                        }
                        visibleNameList.Add(fieldInfo.Name);
                    }
                    UpdateDisplayValue(value);//新别名映射集可能包含当前值, 更改当前值的显示
                }
                else for (int i = 0; i < fieldInfos.Length; i++) visibleNameList.Add(fieldInfos[i].Name);//没有别名
            }
            else//有要隐藏的枚举
            {
                visibleFieldInfoList.Clear();
                if (hasAliasMap)//有别名
                {
                    for (int i = 0; i < fieldInfos.Length; i++)
                    {
                        FieldInfo fieldInfo = fieldInfos[i];
                        T enumValue = (T)fieldInfo.GetValue(null);
                        if (hideFlags.Contains(enumValue)) continue;
                        visibleFieldInfoList.Add(enumValue);
                        if (aliasMap.TryGetValue(enumValue, out string alias))
                        {
                            visibleNameList.Add(alias);
                            aliasDictionary.Add(fieldInfo.Name, alias);
                            continue;
                        }
                        visibleNameList.Add(fieldInfo.Name);
                    }
                    UpdateDisplayValue(value);//新别名映射集可能包含当前值, 更改当前值的显示
                }
                else//没有别名
                {
                    for (int i = 0; i < fieldInfos.Length; i++)
                    {
                        FieldInfo fieldInfo = fieldInfos[i];
                        T enumValue = (T)fieldInfo.GetValue(null);
                        if (hideFlags.Contains(enumValue)) continue;
                        visibleFieldInfoList.Add(enumValue);
                        visibleNameList.Add(fieldInfo.Name);
                    }
                }
            }
            dropdownField.choiceList = visibleNameList;
        }

        private void UpdateDisplayValue(T value)
        {
            string valueName = value.ToString();
            if (hasAliasMap && aliasDictionary.TryGetValue(valueName, out string alias)) valueName = alias;
            dropdownField.SetValueWithoutNotify(valueName);
        }
        private void ClickCallback(ClickEvent clickEvent)
        {
            clickEvent.StopPropagation();
        }
        private void OnNameChangeCallback(string newValue)
        {
            base.SetValue(visibleFieldInfoList[visibleNameList.IndexOf(newValue)]);
        }
    }
}